<!-- 自定义编辑框 -->
<template>
  <div class="m-textarea" ref="textareaRef">
    <div id="yzj__text_area"
         class="m-text-div"
         draggable="true"
         ref="editText"
         @keydown.enter="enterHandler"
         @input="change"
         @click="clickHandler"
         :style="{minHeight: `${props.minHeight}px`, height: `${props.height}px`}"
         contenteditable="true">
    </div>
  </div>
</template>

<script lang="ts" setup>
/** JS */
import {ref, reactive, defineProps, watch, onMounted, withDefaults, defineEmits} from 'vue';
import ImageCompress from '@/utils/ImageCompress';
import toast from '@/utils/Toast';

interface EditTextarea {
  minHeight: number,
  height: number,
  updateValues: string,
  updateImages: any[]
}

/** 钩子 */
const props = withDefaults(defineProps<EditTextarea>(), {
  height: 300,
  updateValues: ''
}), emits = defineEmits(['inputValue', 'imageValue', 'onEnterClick']);
const $ = require("jquery"), imageCompress = new ImageCompress();

let textareaRef = ref(null);
/** 参数属性 */
const renderValues = reactive({
  input: '',
  images: [] as any[]
});
// 监听做清空数据
watch(props, (n) => {
  if (n.updateValues.trim() === '') {
    renderValues.input = '';
    renderValues.images = [];
    $('#yzj__text_area').empty();
    // editElement.innerHTML = '';
  }
  if (n.updateImages.length === 0) {
    renderValues.images = [];
  }
}, {deep: true});
/**
 * 监听编辑器事件
 */
let editElement, $edit = ref(null), editText = ref(null);
/**
 * 输入操作
 * @param e
 */
const change = (e) => {
      if (!e) return;
      const target = e.target;
      if ($edit.value == null) {
        $edit.value = $(target);
      }
      if (!editElement) {
        editElement = target;
      }
      renderValues.input = target.innerHTML;
      emits('inputValue', renderValues.input);
    },
    /**
     * 更新光标位置
     */
    updateRange = () => {
      if (editElement) {
        const range = document.createRange();
        // 获取文本位置
        range.selectNodeContents(editElement);
        range.collapse(false);
        let select = window.getSelection();
        // 移除所有光标，加入指定位置。
        if (select) {
          select.removeAllRanges();
          select.addRange(range);
        }
      }
    },
    /**
     * enter 操作
     * <p> alt+enter 为换行, enter 为发送
     * @param e 事件
     */
    enterHandler = (e) => {
      if (!e) return;

      const target = e.target;
      if ($edit.value == null) {
        $edit.value = $(target);
      }
      if (!editElement) {
        editElement = target;
      }
      const isEnter = e.code.indexOf('Enter') !== -1;
      e.preventDefault();
      // alt + enter 换行
      if (e.altKey && isEnter) {
        e.returnValue = true;
        let div = document.createElement('div'), br = document.createElement('br');
        div.appendChild(br);
        target.appendChild(div);
        renderValues.input = target.innerHTML;
        updateRange();
        emits('inputValue', renderValues.input);
      } else if (isEnter) {
        emits('onEnterClick', renderValues);
      }
    },
    /**
     * 激活点击输入框
     */
    clickHandler = () => {
      if (textareaRef.value) {
        const $el = $(textareaRef.value);
        $el.addClass('m-textarea-focus');
      }
    },
    /**
     * 添加图片
     */
    add = (file, edit) => {
      if (file.type.indexOf('image') === -1) {
        toast.warn('读取失败', '目前聊天室仅支持图片类型噢~', 1500);
        return;
      }
      const size = file.size;
      if (size > imageCompress.mbToByteSize(8)) {
        toast.error('读取失败', `${file.name} 太大啦，不能大于8MB哦~`, 1500);
        return;
      }
      let limitedSize;
      if (size > imageCompress.mbToByteSize(6)) {
        limitedSize = size / 1024 * 0.15;
      } else if (size > imageCompress.mbToByteSize(5)) {
        limitedSize = size / 1024 * 0.2;
      } else if (size > imageCompress.mbToByteSize(4)) {
        limitedSize = size / 1024 * 0.25;
      } else if (size > imageCompress.mbToByteSize(3)) {
        limitedSize = size / 1024 * 0.3;
      } else if (size > imageCompress.mbToByteSize(2)) {
        limitedSize = size / 1024 * 0.5;
      } else if (size > imageCompress.mbToByteSize(1)) {
        limitedSize = size / 1024 * 0.7;
      } else {
        limitedSize = size / 1024;
      }
      imageCompress.compress(file, limitedSize).then(res => {
        const reader = new FileReader();
        reader.readAsDataURL(res.file);
        reader.onload = function () {
          // 往 edit 中添加 img
          let img = new Image(60);
          img.src = this.result as string;
          img.classList.add('flex', 'justify-content-center')
          edit.appendChild(img);
          // 加入图片数组
          let fd = new FormData();
          fd.append('file', res.file);
          renderValues.images.push(fd);
          renderValues.input = edit.innerHTML;
          // updateRange();
          emits('inputValue', renderValues.input);
          emits('imageValue', renderValues.images);
        }
      })
    }

onMounted(() => {
  if (editText.value) {
    $edit.value = $(editText.value);
  }
  document.ondragover = (e) => e.preventDefault();
  document.ondrop = (e) => e.preventDefault();
  if ($edit.value) {
    const edit: HTMLElement = $edit.value[0];
    // 监听拷贝\拖拉事件
    if (edit) {
      edit.ondragover = (e) => e.preventDefault();
      /**
       * 监听拖拉
       * @param e
       */
      edit.ondrop = function (e: DragEvent) {
        e.preventDefault();
        if (e && e.dataTransfer) {
          let list = e.dataTransfer.files;
          for (let i = 0; i < list.length; i++) {
            add(list[i], edit);
          }
        }
      }
      /**
       * 监听拷贝
       */
      $(edit).bind('paste', (e) => {
        let cbd = e.originalEvent.clipboardData;
        for (let i = 0; i < cbd.items.length; i++) {
          let item = cbd.items[i];
          if (item.kind === 'file') {
            if (item.type.indexOf('image') > -1) {
              // 如果是图片类型则取消默认拷贝事件
              e.preventDefault();
              let file = item.getAsFile();
              add(file, edit);
              updateRange();
            } else {
              toast.error('读取失败', '文件类型仅支持图片类型哦~', 1500);
            }
          }
        }
      })
    }
  }

  // 动态遍历 div 用于聚焦
  $(document).click(function (e) {
    const textarea = textareaRef.value;
    if (textarea) {
      const target = e.target;
      const el = textarea;
      const divs = $(el).find('div');
      for (let div of divs) {
        if (div === target) {
          if (!$(el).hasClass('m-textarea-focus')) {
            $(el).addClass('m-textarea-focus');
          }
          break;
        } else {
          if ($(el).hasClass('m-textarea-focus')) {
            $(el).removeClass('m-textarea-focus');
          }
        }
      }
    }
  })
})
</script>

<style lang="less" scoped>
.m-textarea {
  padding: 5px;
  border: 1px solid #BDBDBD;
  border-radius: 5px;
  background-color: white;
  transition: all .3s ease-in-out;
  width: 100%;
  overflow-y: hidden;
  cursor: text;
}

.m-textarea-focus {
  box-shadow: 0 0 5px #FF4500;
}

.m-text-div {
  outline: none;
}

.m-textarea:focus {
  box-shadow: 0 0 5px #FF4500;
}
</style>
